package com.jushu.storbox.task.tqueue;

import java.io.File;
import java.util.Random;

import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.jushu.storbox.R;
import com.jushu.storbox.ShareDriveApplication;
import com.jushu.storbox.callback.ICallback;
import com.jushu.storbox.constant.ClientConfig;
import com.jushu.storbox.constant.Constant;
import com.jushu.storbox.constant.ReceiverConstent;
import com.jushu.storbox.database.DAOFactory;
import com.jushu.storbox.database.IDownloadFileDao;
import com.jushu.storbox.database.IFileDao;
import com.jushu.storbox.entities.DownloadObject;
import com.jushu.storbox.entities.FileFolderInfo;
import com.jushu.storbox.entities.FileInfo;
import com.jushu.storbox.filesystem.FileManagerFactory;
import com.jushu.storbox.filesystem.iFileManager;
import com.jushu.storbox.manager.CatchManager;
import com.jushu.storbox.manager.DownloadTaskManager;
import com.jushu.storbox.service.FileHelper;
import com.jushu.storbox.util.DirectoryUtil;
import com.jushu.storbox.util.FileUtil;
import com.jushu.storbox.util.LogUtil;
import com.huawei.sharedrive.sdk.android.exception.ClientException;
import com.huawei.sharedrive.sdk.android.serviceV2.AbsDownloadProcessorV3;
import com.huawei.sharedrive.sdk.android.serviceV2.FileClientV2;

public class DownloadTask extends PriorityTask {

    private final static String TAG = "DownloadTask";

    private Context context;

    private Random random;

    private int priority;

    // private final String id;

    private String ownerID;

    private String fileID;

    private String objectId;

    private String authorization;

    private long startIndex;

    private String path;

    private String tempPath;

    private DownloadCallbackWrapper callback = new DownloadCallbackWrapper();

    private FileClientV2 client = null;

    private String folderID;

    private long fileSize;

    private boolean isCancel = false;

    private boolean isStoped = false;

    private boolean isUpdateSync;

    FileFolderInfo downloadNode = null;
    DownloadObject downloadObj = null;

    IFileDao fileDao;
    IDownloadFileDao downloadDao;

    public DownloadTask(Context context, ICallback callback, FileFolderInfo downloadNode, boolean isUpdateSync) {
        this.downloadNode = downloadNode;
        downloadObj = new DownloadObject();
        downloadObj.fromFileFolderInfo(downloadNode);
        initDownloadTask(context, callback, isUpdateSync);
    }

    public DownloadTask(Context context, long startIndex, ICallback callback, DownloadObject downloadObj, boolean isUpdateSync) {
        this.downloadObj = downloadObj;
        initDownloadTask(context, callback, isUpdateSync);
    }

    private void initDownloadTask(Context context, ICallback callback, boolean isUpdateSync) {
        this.context = context;
        random = new Random();
        this.priority = Math.abs(random.nextInt() % 10);
        this.ownerID = downloadObj.getOwnerBy();
        this.folderID = downloadObj.getParentId();
        this.fileID = downloadObj.getId();
        this.startIndex = 0;
        this.isCancel = false;
        this.isUpdateSync = isUpdateSync;
        this.objectId = downloadObj.getObjectId();

        fileDao = DAOFactory.instance(context).getFileDao();
        downloadDao = DAOFactory.instance(context).getDownloadFileDao();

        tempPath = DirectoryUtil.generateTempFileDownloadPath(context, downloadObj.getId(), downloadObj.getFileName());
        if (null != callback) {
            this.callback.registerCallback(callback);
        }
        if (null == client) {
            client = FileClientV2.getInstance();
        }
        this.fileSize = downloadObj.getFileSize();
        Intent intent = new Intent(ReceiverConstent.DOWNLOAD_REFRESH);
        context.sendBroadcast(intent);

        this.path = DirectoryUtil.generateFileDownloadPath(context, downloadObj);

        setSync(isUpdateSync);
        setTransStatus(Constant.DOWNLOAD_ISWAITING_UPDATE_DB);
        downloadObj.setSync(isUpdateSync);
        downloadObj.setTransStatus(Constant.TRANSLATE_IS_WAITING);
        downloadDao.insertFile(downloadObj);
    }

    public void initRunEnveriment() {
        isCancel = false;
        isStoped = false;

        if (downloadDao == null) {
            downloadDao = DAOFactory.instance(context).getDownloadFileDao();
        }

        if (fileDao == null) {
            fileDao = DAOFactory.instance(context).getFileDao();
        }

        if (client == null) {
            client = FileClientV2.getInstance();
        }

        this.authorization = ShareDriveApplication.getInstance()
                .getAuthorization();

        CatchManager.getInstance().putDownloadObject(downloadObj);
        downloadObj.setDownloadTask(this);
    }

    public FileFolderInfo getDownloadNode() {
        if (downloadNode == null) {
            downloadNode = fileDao.getFile(downloadObj.getOwnerBy(),
                    downloadObj.getId());
            if (downloadNode == null) {
                downloadNode = new FileInfo();
            }
        }
        return downloadNode;
    }

    public void setSync(boolean syncState) {
        if (syncState) {
            fileDao.updateSyncStatus(ownerID, fileID,
                    Constant.DOWNLOAD_STATUS_CACHE_DB);
        } else {
            fileDao.updateSyncStatus(ownerID, fileID,
                    Constant.DOWNLOAD_STATUS_NOCACHE_DB);
        }
        getDownloadNode().setSync(syncState);
        getDownloadNode().notifyChange();
    }

    public void setTransStatus(int transState) {
        fileDao.updateTransStatus(ownerID, fileID, transState);
        getDownloadNode().setTransStatus(transState);
        getDownloadNode().notifyChange();
    }

    public void setProgress(int progress) {
        Log.i("test", "progress = " + progress);
        getDownloadNode().setProgress(progress);
        getDownloadNode().notifyChange();
    }

    public void setDownloadObjectState(int transState) {
        downloadObj.setTransStatus(transState);
        downloadObj.notifyChange();
        downloadDao.updateDownloadObject(downloadObj);
    }

    public String getId() {
        return fileID;
    }

    public String getOwnerID() {
        return ownerID;
    }

    public String getFolderID() {
        return folderID;
    }

    @Override
    public int getPriority() {
        return priority;
    }

    @Override
    public void setPriority(int priority) {
        this.priority = priority;
    }

    @Override
    public void setTipTopPriority() {
        this.priority = Integer.MAX_VALUE;
    }

    public void cancelDownloadTask() {
        this.isCancel = true;
    }

    public void stopDownloadTask() {
        isStoped = true;
    }

    public String getPath() {
        return path;
    }

    public long getFileSize() {
        return fileSize;
    }

    @Override
    public void run() {
        initRunEnveriment();

        try {
            if (null != client && !isStoped && !isCancel) {
                setDownloadObjectState(Constant.TRANSLATE_IS_STARTED);

                DownloadTaskManager.addRunningTask(this);
                DownloadTaskManager.removeWaitingTask(this);
                if (null == this.fileID || "".equalsIgnoreCase(this.fileID.trim())) {
                    Exception e = new Exception("fileID is null");
                    LogUtil.e(TAG,
                            "[" + tempPath + "]" + e.getLocalizedMessage());
                    callback.onFailure(e.fillInStackTrace(),
                            Constant.DOWNLOAD_FAIL_FILEDID_NULL_CODE);// onFail
                    DownloadTaskManager.addFailTask(DownloadTask.this);
                } else {
                    client.download(ownerID, fileID, objectId, authorization, new DownloadProcessor());
                }
            } else if (isStoped) {
                setTransStatus(Constant.DOWNLOAD_ISWAITING_UPDATE_DB);
                setDownloadObjectState(Constant.TRANSLATE_IS_STOPED);
                DownloadTaskManager.removeTask(DownloadTask.this);
                DownloadTaskManager.addFailTask(DownloadTask.this);
                callback.onStop();
            } else if (isCancel) {
                setSync(false);
                setTransStatus(Constant.DOWNLOAD_CANCEL_UPDATE_DB);
                downloadDao.deleteFile(fileID, ownerID);
                callback.onCanceled();
                DownloadTaskManager.removeTask(DownloadTask.this);
            }
        } catch (Exception e) {
            e.printStackTrace();
            LogUtil.e(TAG, "[" + tempPath + "]" + e.getLocalizedMessage());
            setTransStatus(Constant.DOWNLOAD_FAIL_UPDATE_DB);
            setDownloadObjectState(Constant.TRANSLATE_IS_FAILURED);
            DownloadTaskManager.removeTask(DownloadTask.this);
            DownloadTaskManager.addFailTask(DownloadTask.this);
            callback.onFailure(e.fillInStackTrace(),
                    Constant.DOWNLOAD_THREAD_ERROR_CODE);
        } finally {
            callback.onDettach();
            CatchManager.getInstance().removeDownloadObject(downloadObj);
        }
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((fileID == null) ? 0 : fileID.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        DownloadTask other = (DownloadTask) obj;
        if (fileID == null) {
            if (other.fileID != null)
                return false;
        } else if (!fileID.equalsIgnoreCase(other.fileID))
            return false;
        return true;
    }

    // callback
    public void setCallback(ICallback callback) {
        if (null != callback) {
            this.callback.registerCallback(callback);
        }
    }

    public void remveCallback(ICallback callback) {
        if (null != callback) {
            this.callback.unRegisterCallback(callback);
        }
    }

    private String getFilePath() {
        return path;
    }

    public boolean isRequestUpdateSync() {
        return isUpdateSync;
    }

    class DownloadProcessor extends AbsDownloadProcessorV3 {
        File file = null;

        @Override
        protected void onDownloadStart(long currentPosition, long maxSize) {
            setTransStatus(Constant.DOWNLOAD_ISRUNNING_UPDATE_DB);
            setDownloadObjectState(Constant.TRANSLATE_IS_RUNNING);
            callback.onStart();
        }

        @Override
        protected long getStartIndex(String objectId) {
            if (startIndex > 0) {
                LogUtil.i(TAG, "[NONMDM] start Index is: " + startIndex);
                return startIndex;
            }
            File file = getTargetFile();
            if (file.exists()) {
                LogUtil.i(TAG, "[NONMDM] temp file is exist!");
                startIndex = downloadObj.getCurrentSize();
            } else {
                LogUtil.i(TAG, "[NONMDM] temp file is not exist!");
                startIndex = 0;
            }
            LogUtil.i(TAG, "[NONMDM] start Index is: " + startIndex);
            return startIndex;
        }

        @Override
        protected long getFileSize(String objectId) {
            LogUtil.i(TAG, "getFileSize-> " + fileSize);
            return fileSize;
        }

        @Override
        protected File getTargetFile() {
            if (file == null) {
                file = new File(tempPath);
            }
            return file;
        }

        @Override
        protected void onProgress(int progress,
                                  long currentSize, long totalSize) {
            startIndex = currentSize;

            downloadObj.setCurrentSize(currentSize);
            downloadObj.setCurrentPaogress(progress);
            downloadObj.setTransStatus(Constant.TRANSLATE_IS_RUNNING);
//            downloadObj.notifyChange();
            downloadDao.updateDownloadObject(downloadObj);

            setProgress(progress);

            callback.onProgress(progress, currentSize,
                    totalSize);
        }

        @Override
        protected boolean requestCancelTask() {
            return DownloadTask.this.isCancel;
        }

        @Override
        protected void onTaskCanceled() {
            Log.i("liuxiang", "cancel run");
            LogUtil.e(TAG,
                    "[" + tempPath + "]"
                            + "cancel cache success!");
            setTransStatus(Constant.DOWNLOAD_CANCEL_UPDATE_DB);
            setSync(false);
            downloadDao.deleteFile(fileID, ownerID);

            DownloadTaskManager.removeTask(DownloadTask.this);
            //delete file
            iFileManager mdmTools = FileManagerFactory.getFileManager(context);
            mdmTools.deleteFile(tempPath);

            callback.onCanceled();
        }

        @Override
        protected boolean requestStopTask() {
            return DownloadTask.this.isStoped;
        }

        @Override
        protected void onTaslStoped() {
            Log.i("liuxiang", "cancel run");
            setTransStatus(Constant.DOWNLOAD_ISWAITING_UPDATE_DB);
            setDownloadObjectState(Constant.TRANSLATE_IS_STOPED);

            DownloadTaskManager.addFailTask(DownloadTask.this);
            DownloadTaskManager.removeTask(DownloadTask.this);

            callback.onStop();
        }

        @Override
        protected void onTaskFailure(int errorCode, String errorMsg) {
            LogUtil.e(TAG, "[" + tempPath + "] code:" + errorCode + ", msg:" + errorMsg);
            setTransStatus(Constant.DOWNLOAD_FAIL_UPDATE_DB);
            setDownloadObjectState(Constant.TRANSLATE_IS_FAILURED);

            DownloadTaskManager.addFailTask(DownloadTask.this);
            DownloadTaskManager.removeTask(DownloadTask.this);

            ClientException e = new ClientException(errorCode, errorMsg);
            callback.onFailure(e, e.getStatusCode());
        }

        @Override
        protected void onTaskSuccess() {
            long realFileSize = file.length();
            if (realFileSize == fileSize) {
                if (FileUtil.moveFile(tempPath, getFilePath())) {
                    downloadObj.setTransStatus(Constant.TRANSLATE_IS_SUCCESS);
                    downloadObj.notifyChange();
                    downloadDao.deleteFile(fileID, ownerID);
                    LogUtil.i(TAG, "[" + tempPath
                            + "]onSuccess:" + file.length());

                    FileFolderInfo info = getDownloadNode();
                    info.setTransStatus(Constant.DOWNLOAD_SUCCESS_UPDATE_DB);
                    info.setContentSyncState(Constant.SYNC_STATUS_TRUE);
                    fileDao.updateTransStatus(ownerID, fileID,
                            Constant.DOWNLOAD_SUCCESS_UPDATE_DB);
                    if (info.getIdentity() != null) {
                        fileDao.syncFileInfoToLocal(info);
                    }
                    fileDao.updateLocalSaveState(info);
                    info.notifyChange();
                    callback.onSuccess();// onSuccess
                } else {
                    LogUtil.e(TAG, "move file failed");
                }
            } else {
                LogUtil.e(TAG, "downloaded file is diety\n " +
                        "realLenght:>" + realFileSize + ", hopeLenght:" + fileSize);
            }
            DownloadTaskManager.removeTask(DownloadTask.this);
        }

        @Override
        protected void InputStreamIsInvalid() {
            LogUtil.e(TAG, "input stream is null");
        }

        @Override
        protected long getAvalibleSpace() {
            String cahtchPath = DirectoryUtil.getCurrentCachePath(context);
            double freeSpace = FileHelper.getUsingSDCardSize(context,
                    cahtchPath + ClientConfig.CACHE_CONTEXT);
            return (long) freeSpace;
        }

        @Override
        protected void onSystemSpaceNotEnough() {
            setTransStatus(Constant.DOWNLOAD_FAIL_UPDATE_DB);
            setDownloadObjectState(Constant.TRANSLATE_IS_FAILURED);

            String errorMsg = context.getString(R.string.download_file_larger_than_local_cache);
            ClientException e = new ClientException(errorMsg);
            DownloadTaskManager.removeTask(DownloadTask.this);
            callback.onFailure(e, Constant.DOWNLOAD_FAIL_FILE_LARGERTHAN_CACHESIZE);
            Intent intent = new Intent(ReceiverConstent.DOWNLOAD_CATCH_NOT_ENOUGH);
            context.sendBroadcast(intent);
            super.onSystemSpaceNotEnough();
        }

        @Override
        protected void onAssignSpaceFailure() {
            String error = context.getString(R.string.assign_file_space_failure);
            setTransStatus(Constant.DOWNLOAD_FAIL_UPDATE_DB);
            setDownloadObjectState(Constant.TRANSLATE_IS_FAILURED);

            ClientException e = new ClientException(Constant.DOWNLOAD_FAIL_FILE_ASSIGN_CACHESIZE, error);
            DownloadTaskManager.removeTask(DownloadTask.this);
            callback.onFailure(e, e.getStatusCode());
            super.onAssignSpaceFailure();
        }
    }

    ;
}